﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using IntelligentDecisioning.SharePoint.Definition.Fields;
using Microsoft.Practices.SPG.Common.ServiceLocation;
using Microsoft.Practices.SPG.Common.Logging;
using IntelligentDecisioning.SharePoint.repositories;
using IntelligentDecisioning.SharePoint.BusinessEntities;
using Microsoft.Practices.SPG.Common.ListRepository;
using IntelligentDecisioning.SharePoint.Helpers;

namespace IntelligentDecisioning.SharePoint.Definition
{
    /// <summary>
    /// The definition of a list that we want to provision in sharepoint.
    /// 
    /// Defining a list in code allows us to built up a hierachy of reusable 
    /// tested list definitions.
    /// 
    /// Field Guids are used for to create field mappings that allow items
    /// to be read from written to lists without writing code by using the
    /// the sharepoint patterns and practices entity mapping functionality
    /// 
    /// Field guids have been taken form the <BaseType/> definitions of the 
    /// 12/TEMPLATE/GLOBAL/XML/ONET.XML file. There are many hidden fields
    /// for each kist type. Only the fields that are felt to be useful
    /// have been included.
    /// </summary>
    public class SharePointList
    {
        #region Constants

        // List Field ID's
        public static Guid ID_GUID = new Guid("1d22ea11-1e32-424e-89ab-9fedbadb6ce1");
        public static Guid CONTENT_TYPE_ID_GUID = new Guid("03e45e84-1992-4d42-9116-26f756012634");
        public static Guid CONTENT_TYPE_GUID = new Guid("c042a256-787d-4a6f-8a8a-cf6ab767f12d");
        public static Guid TITLE_GUID = new Guid("fa564e0f-0c70-4ab9-b863-0177e6ddd247");
        public static Guid MODIFIED_GUID = new Guid("28cf69c5-fa48-462a-b5cd-27b6f9d2bd5f");
        public static Guid CREATED_GUID = new Guid("8c06beca-0777-48f7-91c7-6da68bc07b69");
        public static Guid AUTHOR_GUID = new Guid("1df5e554-ec7e-46a6-901d-d85a3881cb18");
        public static Guid EDITOR_GUID = new Guid("d31655d1-1d5b-4511-95a1-7a09e9b75bf2");
        //UI version
        public static Guid VERSION_GUID = new Guid("7841bf41-43d0-4434-9f50-a673baef7631");

        //TODO: Figure out attachments
       

        // List Field Internal Names
        public static String ID = "ID";
        public static String CONTENT_TYPE_ID = "ContentTypeId";
        public static String CONTENT_TYPE = "ContentType";
        public static String TITLE = "Title";
        public static String MODIFIED = "Modified";
        public static String CREATED = "Created";
        public static String AUTHOR = "Author";
        public static String EDITOR = "Editor";
        public static String VERSION = "_UIVersionString";

        // Internal field names to use in views
        /// <summary>
        /// Used to display the paperclip attachments icon in a list view
        /// </summary>
        public static String ATTACHMENTS = "Attachments";
        /// <summary>
        /// Used to display the item title with dropdown ECB menu in a list view
        /// </summary>
        public static String TITLE_LINKED_TO_ITEM_WITH_EDIT_MENU = "LinkTitle";

        /// <summary>
        /// Used to show the approval status of an item in a list view. 
        /// This is only valid when "require content approval" is enabled for the list
        /// </summary>
        public static String APPROVAL_STATUS = "_ModerationStatus";

        /// <summary>
        /// User to show the approvers comments for an item in a list view.
        /// This is only valid when "require content approval" is enabled for the list
        /// </summary>
        public static String APPROVER_COMMENTS = "_ModerationComments";

        /// <summary>
        /// Used to show the title of the item in the list with hyperlink but no ECB menu.
        /// </summary>
        public static String TITLE_LINKED_TO_ITEM = "LinkTitleNoMenu";
        
        /// <summary>
        /// Used to show the document icon for an item in a list
        /// </summary>
        public static String TYPE_LINKED_TO_ICON = "DocIcon";

        /// <summary>
        /// Used to show the edit item icon in a list
        /// </summary>
        public static String EDIT_ITEM_ICON = "Edit";


        #endregion

        #region Static constructor

        static SharePointList()
        {
            IdToInternalNameFieldMappings = new Dictionary<Guid, string>();

            //IdToInternalNameFieldMappings.Add(ID_GUID, ID);
            //IdToInternalNameFieldMappings.Add(TITLE_GUID, TITLE);

            InternalNameToIdFieldMappings = new Dictionary<string, Guid>();
        }


        #endregion

        #region Static Properties

        static public Dictionary<Guid,String> IdToInternalNameFieldMappings { get; set; }
        static public Dictionary<String, Guid> InternalNameToIdFieldMappings { get; set; }

        #endregion

        #region Properties

        // The name of the list to provision
        public string Name { get; set; }

        // The description of the list to provision
        public String Description { get; set; }

        // Allows the list to be initially provisoined from
        // an exisitng sharepoint list template (Tasks, ProjectTasks etc)
        public SPListTemplateType TemplateType { get; set; }

        // Set to true to enable versioning on the list
        public bool EnableVersioning { get; set; }

        // Set to true to add the list to the quick launch on the site
        public bool OnQuickLaunch { get; set; }

        // A collection of fields to add to the list
        public List<Field> Fields { get; set; }
        
        // A collection of site columns to add to the list
        public List<Field> SiteColumns { get; set; }

        // Set to true to enable content types on the list
        public bool EnableContentTypes { get; set; }

        // A collection of content types to add to the list
        public List<SPContentTypeId> ContentTypes { get; set; }

        // Set to true to retain the default content type on the list
        public bool RetainDefaultContentType { get; set; }

        // Set to true to force the list to be deleted and recreated if it already exists
        public bool OverwriteIfPresent { get; set; }

        // A collection of views to add to the list
        public List<SharePointListView> Views { get; set; }

        // Set to true to enable minor versions on the list
        public bool MinorVersions { get; set; }

        // Set to true to require content approval on the list
        public bool RequireContentApproval { get; set; }

        // Set to true to email enable ther list
        public bool EmailEnabled { get; set; }

        // Sets the email alias for an email enabled list
        public String EmailAlias { get; set; }

        // A list of event handlers to register against this list
        public List<SharePointListItemEventHandler> EventHandlers { get; set; }

        // A list of workflow associations to add to this list
        public List<WorkflowAssociation> Workflows { get; set; }

        #endregion

        #region Data

        protected ILogger _logger;

        #endregion

        #region Constructor

        public SharePointList(String name)
        {
            _logger = SharePointServiceLocator.Current.GetInstance<ILogger>();

            Name = name;
            Description = name;
            TemplateType = SPListTemplateType.GenericList;
            ContentTypes = new List<SPContentTypeId>();
            Fields = new List<Field>();
            SiteColumns = new List<Field>();
            Views = new List<SharePointListView>();
            EventHandlers = new List<SharePointListItemEventHandler>();
            Workflows = new List<WorkflowAssociation>();
            OnQuickLaunch = true;
            EnableVersioning = false;
            EnableContentTypes = false;
        }

        #endregion

        #region List Operations

        #region Get Items

        /// <summary>
        /// A generic method to get items from a list
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="targetSite"></param>
        /// <param name="targetWeb"></param>
        /// <returns></returns>
        public List<T> GetItems<T>(SPSite targetSite, SPWeb targetWeb, SPQuery query, SPView view) where T : ListItemEntityBase, new()
        {
            //Create a new mapper to map between the current business entity and
            // the fields in the underlying sharepoint list
            ListItemFieldMapper<T> entityFieldMapper = new ListItemFieldMapper<T>();

            // Add the field mappaings according to the type of list we are
            entityFieldMapper.FieldMappings = GetFieldMappings();

            // Create a generic list to store our bsuiness entities as we 
            // retrieve them form our sharepoint list
            List<T> listItemEntities = new List<T>();

            // Get the sharepoint list for the current context
            IDListHelper listHelper = new IDListHelper(targetSite, targetWeb);
            SPList sharepointList = listHelper.GetList(Name);

            SPListItemCollection items = null;

            if (query == null && view == null)
            {
                items = sharepointList.Items; // all items (no query or view)
            }
            else
                if (view == null)
                {

                    items = sharepointList.GetItems(query); // all match query (no view) 
                }
                else if (query == null)
                {
                    items = sharepointList.GetItems(view); // all match view (no query)
                 }
                else
                {
                    items = sharepointList.GetItems(query, view.Title); // all match query in specified view
                }

            // Create a new business entity for each item found
            foreach (SPListItem item in items)
            {
                T itemEntity = entityFieldMapper.CreateEntity(item);
                listItemEntities.Add(itemEntity);
            }

            // Return the business entities that we have created
            return listItemEntities;

        }


        /// <summary>
        /// Generic method to add an item to the list
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="targetSite"></param>
        /// <param name="targetWeb"></param>
        /// <returns></returns>
        public T AddItem<T>(SPSite targetSite, SPWeb targetWeb, T entity) where T : ListItemEntityBase, new()
        {
            //Create a new mapper to map between the current business entity and
            // the fields in the underlying sharepoint list
            ListItemFieldMapper<T> entityFieldMapper = new ListItemFieldMapper<T>();

            // Add the field mappaings according to the type of list we are
            entityFieldMapper.FieldMappings = GetUpdateFieldMappings();

            // Get the sharepoint list for the current context
            IDListHelper listHelper = new IDListHelper(targetSite, targetWeb);
            SPList sharepointList = listHelper.GetList(Name);

            //Create a new list item and populate it with the entity
            SPListItem listItem = sharepointList.Items.Add();
            entityFieldMapper.FillSPListItemFromEntity(listItem, entity);

            //TODO: generate a new entity using the id of the sharepoint list item

            return entity;

        }
   

        #endregion

        #endregion

        #region Field Mappings

        /// <summary>
        /// Returns the set of field mappings used to read data from the sharepoint
        /// list in order to populate the corresponding entity
        /// </summary>
        /// <returns></returns>
        public virtual List<FieldToEntityPropertyMapping> GetFieldMappings()
        {
            List<FieldToEntityPropertyMapping> mappings = new List<FieldToEntityPropertyMapping>();
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.ID_GUID, "Id"));
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.TITLE_GUID, "Title"));
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.CREATED_GUID, "Created"));
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.MODIFIED_GUID, "LastModified"));
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.AUTHOR_GUID, "Author"));
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.EDITOR_GUID, "Editor"));
            return mappings;
        }


        /// <summary>
        /// Returns the set of field mappings used to write data from the entity to the sharepoint list
        /// </summary>
        /// <returns></returns>
        public virtual List<FieldToEntityPropertyMapping> GetUpdateFieldMappings()
        {
            List<FieldToEntityPropertyMapping> mappings = new List<FieldToEntityPropertyMapping>();
            mappings.Add(new FieldToEntityPropertyMapping(SharePointList.TITLE_GUID, "Title"));
            return mappings;
        }

        #endregion
    }
}
